package vn.conghuy.talkwithme.responsor.responsor;

import java.util.ArrayList;
import java.util.HashMap;

import vn.conghuy.talkwithme.data.sqlmodel.SqlData;
import vn.conghuy.talkwithme.data.sqlmodel.StaticInfoModel;
import vn.conghuy.talkwithme.data.sqlmodel.TemplatePair;
import vn.conghuy.talkwithme.utils.Utils;

public class ParamTemplateResponsor extends Responsor {
	
	HashMap<String, String> mapParams;
	private static final String LEFT_SQUARE_BRACKET = "[";
	private static final String RIGHT_SQUARE_BRACKET = "]";
	private static final String LEFT_SHARP_BRACKET = "<";
	private static final String RIGHT_SHARP_BRACKET = ">";
	
	public ParamTemplateResponsor() {
		super();
		mapParams = new HashMap<String, String>();
	}
	@Override
	public String response(String request) {
		int askNamesLength = SqlData.askNames.length;
		for(int i = 0; i < askNamesLength; i++){
			String template = SqlData.askNames[i];
			if(isParamTemplate(template)){
				if(compare(template, request, mapParams)){
					
					//get answer template
					String[] answerNames = TemplatePair.getAnswerByAskName(template);
					if(answerNames != null){
						String answer = Utils.getRandomString(answerNames);
						answer = parseAnswer(answer, mapParams);
						return parseStaticInfoForAnswer(answer);
					}
				}
			}
		}
		return super.response(request);
	}
	
	/**
	 * Compare template with request and get parameters keys and values.
	 * Template is a String like "I love [object] so much", "[object]" is param element.
	 * 
	 * @param template template input by programmer
	 * @param request request input by user in running
	 * @param mapParams hashmap of params, store keys and values of params
	 * @return return true if request match template
	 */
	boolean compare(String template, String request, HashMap<String, String> mapParams){
		// GET INDICES OF TEMPLATE
		// indices to define elements in request sentence, with information about it is params or not.
		// Ex : "I love [object] so much", has 3 element, "I love", "[object]" and "so much". "[object]" is param element.
		template = Utils.normalizeString(template);
		request = Utils.normalizeString(request);
		mapParams.clear();
		
		ArrayList<Integer> indices = new ArrayList<Integer>();
		ArrayList<Boolean> isParams = new ArrayList<Boolean>();
		if(template.startsWith(LEFT_SQUARE_BRACKET) == false){
			indices.add(0);
			isParams.add(false);
		}
		
		int offset = 0;
		
		int leftSignIndex = template.indexOf(LEFT_SQUARE_BRACKET, offset);
		int rightSignIndex = template.indexOf(RIGHT_SQUARE_BRACKET, offset);
		
		
		while(leftSignIndex != -1 && rightSignIndex != -1){
			indices.add(leftSignIndex);
			isParams.add(true);
			
			offset = rightSignIndex + 2;
			if(template.startsWith(LEFT_SQUARE_BRACKET, offset) == false && offset - 1 < template.length()){
				indices.add(offset);
				isParams.add(false);
			}
			
			leftSignIndex = template.indexOf(LEFT_SQUARE_BRACKET, offset);
			rightSignIndex = template.indexOf(RIGHT_SQUARE_BRACKET, offset);
		}
		
		//COMPARE TEMPLATE WITH REQUEST AND GET PARAM LIST
		int requestOffset = 0;
		int length = indices.size();
		for(int i = 0; i < length; i++){
			int templateOffset = indices.get(i);
			
			// get element in 
			String templateElement = null;
			if(i < length - 1){
				int indexAfter = indices.get(i + 1);
				templateElement = template.substring(templateOffset, indexAfter - 1);
			}
			else{
				templateElement = template.substring(templateOffset);
			}
			
			// COMPARE
			// If element is not a param, check request contain that element or not. If request contain
			// element, calculate offset and continue. Else, return false.
			// If element is param, get params key from template and param value from request
			if(isParams.get(i) == false){
				if(request.startsWith(templateElement, requestOffset)){
					requestOffset += templateElement.length() + 1;
				}
				else{
					return false;
				}
			}
			else{
				String paramKey = templateElement.substring(1, templateElement.length() - 1);
				
				//determine param value
				String nextElement = null;
				if(i + 1 < length){
					int indexAfter = indices.get(i + 1);
					if(i + 2 < length){
						int indexAfter2 = indices.get(i + 2);
						nextElement = template.substring(indexAfter, indexAfter2 - 1);
					}
					else{
						nextElement = template.substring(indexAfter);
					}
					int indexAfterInRequest = request.indexOf(nextElement, requestOffset);
					if(indexAfterInRequest == -1){
						mapParams.clear();
						return false;
					}
					else{
						String paramValue = request.substring(requestOffset, indexAfterInRequest - 1);
						mapParams.put(paramKey, paramValue);
						requestOffset += paramValue.length() + 1;
					}
				}
				else{
					String paramValue = request.substring(requestOffset);
					mapParams.put(paramKey, paramValue);
					requestOffset += paramValue.length() + 1;
				}
			}
		}
		
		// prevent return true when request has tail but template hasn't
		if(requestOffset - 1 < request.length()){
			mapParams.clear();
			return false;
		}
		
		return true;
	}
	
	/**
	 * Create answer string from template and parameters map
	 * @param template template of answer
	 * @param mapParams parameters map will be used in replacing 
	 * @return answer
	 */
	static String parseAnswer(String template, HashMap<String, String> mapParams){
		
		template = Utils.normalizeString(template);
		String answer = ""; 
		
		// GET INDICES OF TEMPLATE
		// indices to define elements in request sentence, with information about it is params or not.
		// Ex : "I love [object] so much", has 3 element, "I love", "[object]" and "so much". "[object]" is param element.
				
		ArrayList<Integer> indices = new ArrayList<Integer>();
		ArrayList<Boolean> isParams = new ArrayList<Boolean>();
		if(template.startsWith(LEFT_SQUARE_BRACKET) == false){
			indices.add(0);
			isParams.add(false);
		}
		
		int offset = 0;
		
		int leftSignIndex = template.indexOf(LEFT_SQUARE_BRACKET, offset);
		int rightSignIndex = template.indexOf(RIGHT_SQUARE_BRACKET, offset);
		
		
		while(leftSignIndex != -1 && rightSignIndex != -1){
			indices.add(leftSignIndex);
			isParams.add(true);
			
			offset = rightSignIndex + 2;
			if(template.startsWith(LEFT_SQUARE_BRACKET, offset) == false && offset - 1 < template.length()){
				indices.add(offset);
				isParams.add(false);
			}
			
			leftSignIndex = template.indexOf(LEFT_SQUARE_BRACKET, offset);
			rightSignIndex = template.indexOf(RIGHT_SQUARE_BRACKET, offset);
		}
		
		int length = indices.size();
		
		for(int i = 0; i < length; i++){
			int templateOffset = indices.get(i);
			
			// get element in 
			String templateElement = null;
			if(i < length - 1){
				int indexAfter = indices.get(i + 1);
				templateElement = template.substring(templateOffset, indexAfter - 1);
			}
			else{
				templateElement = template.substring(templateOffset);
			}
			
			if(isParams.get(i) == false){
				answer += templateElement; 
			}
			else{
				String paramKey = templateElement.substring(1, templateElement.length() - 1);
				answer += mapParams.get(paramKey);
			}
			answer += " ";
		}
		answer = answer.trim();
		
		return answer;
	}
	
	boolean isParamTemplate(String template){
		if(template.contains(LEFT_SQUARE_BRACKET) && template.contains(RIGHT_SQUARE_BRACKET)){
			return true;
		}
		else return false;
	}
	
	/**
	 * Parse answer use static info to replace for sharp bracket parameter
	 * @param answer Answer need parse
	 * @return Answer is parsed
	 */
 	String parseStaticInfoForAnswer(String answer){
		ArrayList<String> lSubString = new ArrayList<String>();
		int indexOpen = answer.indexOf(LEFT_SHARP_BRACKET);
		int indexClose = answer.indexOf(RIGHT_SHARP_BRACKET);
		String sFinal = "";
		while(indexOpen != -1 && indexClose != -1){
			// get substring before LEFT_SHARP_BRACKET
			if(indexOpen > 0){
				String sub1 = answer.substring(0, indexOpen - 1);
				lSubString.add(sub1);
				answer = answer.substring(indexOpen);
				indexClose = indexClose - sub1.length();
			}
			
			//get substring from LEFT_SHARP_BRACKET to RIGHT_SHARP_BRACKET
			if(indexClose > 0){
				String sub2 = answer.substring(0, indexClose);
				lSubString.add(sub2);
				answer = answer.substring(indexClose);
			}
			indexOpen = answer.indexOf(LEFT_SHARP_BRACKET);
			indexClose = answer.indexOf(RIGHT_SHARP_BRACKET);
		}
		if(answer.length() > 0)
			lSubString.add(answer);
		
		for(int i = 0; i < lSubString.size(); i++){
			String sub = lSubString.get(i);
			if(sub.startsWith(LEFT_SHARP_BRACKET)){
				String keyword = sub.substring(1, sub.length()-1);
				String name = StaticInfoModel.getName(keyword);
				sFinal += name;
			}
			else{
				sFinal += sub;
			}
			sFinal += " ";	
		}
			
		return sFinal;
	}
}
